package cn.adelyn.base.secureweb.filter;

import cn.adelyn.base.api.auth.feign.TokenFeignClient;
import cn.adelyn.base.api.auth.pojo.bo.UserInfoInTokenBO;
import cn.adelyn.base.api.rbac.constant.HttpMethodEnum;
import cn.adelyn.base.api.rbac.feign.PermissionFeignClient;
import cn.adelyn.base.api.rbac.pojo.bo.CheckPermissionBO;
import cn.adelyn.base.secureweb.AuthUserContext;
import cn.adelyn.base.secureweb.adapter.AuthConfigAdapter;
import cn.adelyn.base.secureweb.util.HttpHandler;
import cn.adelyn.common.core.response.ResponseEnum;
import cn.adelyn.common.core.response.ServerResponseEntity;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;


import java.io.IOException;
import java.util.List;

/**
 * @author chengze
 * @date 2022/12/7
 * @desc 授权过滤，子系统可以自己实现AuthConfigAdapter接口
 * 		 也可以在 adelyn.auth.unanth-uri 直接配置不需要授权的路径
 */
@Component
@Slf4j
public class WebAuthFilter implements Filter {

	@Autowired
	private AuthConfigAdapter authConfigAdapter;

	@Autowired
	private TokenFeignClient tokenFeignClient;

	@Autowired
	private PermissionFeignClient permissionFeignClient;


	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;

		List<String> unAuthPatterns = authConfigAdapter.unAuthPatterns();

		// todo 进一步区分方法
		// 如果匹配不需要授权的路径，就不需要校验是否需要授权
		if (CollectionUtil.isNotEmpty(unAuthPatterns)) {
			for (String excludePathPattern : unAuthPatterns) {
				AntPathMatcher pathMatcher = new AntPathMatcher();
				if (pathMatcher.match(excludePathPattern, req.getRequestURI())) {
					chain.doFilter(req, resp);
					return;
				}
			}
		}

		// 未登录用户没有token，如果没在unAuthPatterns放行，判为未授权访问
		String token = req.getHeader("Authorization");

		if (StrUtil.isBlank(token)) {
			HttpHandler.printServerResponseToWeb(ServerResponseEntity.fail(ResponseEnum.UNLOGIN));
			return;
		}

		// 校验token，并返回用户信息
		ServerResponseEntity<UserInfoInTokenBO> userInfoInTokenVoServerResponseEntity = tokenFeignClient
				.checkToken(token);
		if (!userInfoInTokenVoServerResponseEntity.isSuccess()) {
			HttpHandler.printServerResponseToWeb(ServerResponseEntity.fail(ResponseEnum.UNLOGIN));
			return;
		}

		UserInfoInTokenBO userInfoInToken = userInfoInTokenVoServerResponseEntity.getData();

		// 需要用户角色权限，就去根据用户角色权限判断是否
		if (!checkRbac(userInfoInToken, req.getRequestURI(), req.getMethod())) {
			HttpHandler.printServerResponseToWeb(ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED));
			return;
		}

		try {
			// 保存上下文
			AuthUserContext.set(userInfoInToken);

			chain.doFilter(req, resp);
		} finally {
			AuthUserContext.clean();
		}

	}

	/**
	 * 用户角色权限校验
	 * @param uri uri
	 * @return 是否校验成功
	 */
	private boolean checkRbac(UserInfoInTokenBO userInfoInToken, String uri, String method) {

		CheckPermissionBO checkPermissionBO = new CheckPermissionBO();
		checkPermissionBO.setUserType(userInfoInToken.getUserType());
		checkPermissionBO.setUri(uri);
		checkPermissionBO.setMethod(HttpMethodEnum.valueOf(method.toUpperCase()).value());

		ServerResponseEntity<Boolean> booleanServerResponseEntity = permissionFeignClient.checkPermission(checkPermissionBO);

		return booleanServerResponseEntity.isSuccess();
	}

}
